home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / tnos / tnos100s / xmodem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-12  |  16.7 KB  |  516 lines

  1. /*
  2.  * A version of Ward Christensen's file transfer protocol for
  3.  * Unix System V or 4.2 bsd.
  4.  *
  5.  *        Emmet P. Gray, ..!ihnp4!uiucuxc!fthood!egray, 16 Aug 85
  6.  *
  7.  * Modified by Sanford Zelkovitz   08/18/86
  8.  * Last modification date = 05/20/87
  9.  * Modified for KA9Q NOS BBS - WA3DSP 2/93
  10.  */
  11.  
  12.  
  13. #include <stdio.h>
  14. #include <io.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <stdarg.h>
  18. #include "dirutil.h"
  19. #include "timer.h" 
  20. #include "socket.h"
  21. #include "mailbox.h"
  22.  
  23. #ifdef XMODEM
  24.  
  25. #ifdef min
  26. #undef min
  27. #endif
  28.  
  29. #define SPEED 2400       /* Serial line Baudrate */
  30.  
  31. #define MAXERRORS 10     /* max number of times to retry */
  32. #define SECSIZE   128    /* CP/M sector, transmission block */
  33. #define CPMEOF    26     /* End Of File (for CP/M) */
  34. #define SOH       1      /* Start Of Header */
  35. #define STX       2      /* Start of 1K block */
  36. #define EOT       4      /* End Of Transmission */
  37. #define ACK       6      /* ACKnowledge */
  38. #define NAK       21     /* Negative AcKnowledge */
  39. #define CAN       24     /* CANcel */
  40. #define BS        8      /* Backspace */ 
  41.  
  42. static int recvfile __ARGS((char*,struct mbx *m));
  43. static int sendfile __ARGS((char*,struct mbx *m));
  44. static int truncate __ARGS((struct mbx *m,char *path,long length));
  45. static char getchar_t __ARGS((int socket));
  46. static void update_crc __ARGS((unsigned char c, unsigned char *crc1, unsigned char *crc2));
  47. static void error __ARGS((struct mbx *m));
  48. static void print_text __ARGS((struct mbx *m,char *fmt, ...));
  49. static void rawmode __ARGS((struct mbx *));
  50. static void restoremode __ARGS((struct mbx *));
  51.  
  52. doxmodem(mode, filename, p)
  53. char mode, *filename;
  54. void *p;
  55. {
  56.         int exit_return=0, oldflush;
  57.         struct mbx *m;
  58.         
  59.         m = (struct mbx *)p;
  60.         oldflush=setflush(m->user,-1);
  61.     
  62.         switch (mode) {
  63.                 case 'r':
  64.                 case 'R':        
  65.                         exit_return=recvfile(filename,m);
  66.                         break;
  67.                 case 's':
  68.                 case 'S':
  69.                         exit_return=sendfile(filename,m);
  70.                         break;
  71.                 default :
  72.                         print_text(m,"Xmodem: Invalid Option\n");
  73.         }
  74.         restoremode(m);
  75.         usputc(m->user,'\n');
  76.         usflush(m->user);
  77.         setflush(m->user,oldflush);
  78.         return(exit_return);
  79. }
  80.  
  81. /* send a file to the remote */
  82. static int
  83. sendfile(tfile, m)
  84. char *tfile;
  85. struct mbx *m;
  86. {
  87.         FILE *fp;
  88.         unsigned char chr, checksum, block, sector[SECSIZE];
  89.         unsigned char crc1, crc2, mode, errcount, errcount2, two_can;
  90.         int i, nbytes, speed=SPEED;
  91.         long size, min, sec;
  92.         
  93.         if ((size=fsize(tfile))==-1){
  94.                 print_text(m,"xmodem: Can't open '%s' for read\n", tfile);
  95.                 return(1);
  96.         }
  97.  
  98.         if (!(fp = fopen(tfile, READ_BINARY))) {
  99.                 print_text(m,"xmodem: Can't open '%s' for read\n", tfile);
  100.                 return(1);
  101.         }
  102.         
  103.         size=(size/128L)+1L;
  104.         sec = size * 128L * 15L / speed;
  105.         min = sec / 60L;
  106.         sec = sec - min * 60L;
  107.         print_text(m,"\nFile open: %d records\n", size);
  108.         print_text(m,"Send time: %ld min, %ld sec at %d baud\n", min, sec, speed);
  109.         print_text(m,"To cancel: use CTRL-X numerous times\n");
  110.         print_text(m,"Waiting receive ready signal\n");
  111.  
  112.         mspause(3000L);
  113.         rawmode(m); 
  114.         errcount = 0;
  115.         mode = 0;
  116.         two_can=0;
  117.         block = 1;
  118.  
  119.         while (errcount < MAXERRORS) {
  120.                 chr = getchar_t(m->user);
  121.                 if (chr == NAK)                        /* checksum mode */
  122.                         break;
  123.                 if (chr == 'C') {                /* CRC mode */
  124.                         mode = 1;
  125.                         break;
  126.                 }
  127.                 if (chr == CAN) {
  128.                         if (two_can)  {
  129.                              mspause(3000L);
  130.                              print_text(m,"\nxmodem: Abort request received\n");
  131.                              fclose(fp);
  132.                              return(1);
  133.                          }
  134.                         two_can=1;
  135.                 } else {       
  136.                         two_can=0;
  137.                 }
  138.  
  139.                 errcount++;
  140.         }
  141.         if (errcount >= MAXERRORS) {
  142.                 mspause(3000L);
  143.                 print_text(m,"xmodem: Timed out on acknowledge\n");
  144.                 fclose(fp);
  145.                 return(1);
  146.         }
  147.         two_can=0;
  148.         while ((nbytes= fread(sector,1,128, fp))!=0) {
  149.                 if (nbytes < SECSIZE) {              /* fill short sector */
  150.                         for (i=nbytes; i < SECSIZE; i++)
  151.                                 sector[i] = CPMEOF;
  152.                 }
  153.                 errcount = 0;
  154.                 while (errcount < MAXERRORS) {
  155.                         usputc(m->user,SOH);        /* the header */
  156.                         usputc(m->user,block);      /* the block number */
  157.                         chr = ~block;
  158.                         usputc(m->user,chr);        /* it's complement */
  159.                         checksum = 0;
  160.                         crc1 = 0;
  161.                         crc2 = 0;
  162.                         for (i=0; i < SECSIZE; i++) {
  163.                                 usputc(m->user,sector[i]);
  164.                                 if (mode)
  165.                                         update_crc(sector[i],&crc1,&crc2);
  166.                                 else
  167.                                         checksum += sector[i];
  168.                         }
  169.                         if (mode) {
  170.                                 update_crc(0,&crc1,&crc2);
  171.                                 update_crc(0,&crc1,&crc2);
  172.                                 usputc(m->user,crc1);
  173.                                 usputc(m->user,crc2);
  174.                         
  175.                         }
  176.                         else
  177.                                 usputc(m->user,checksum);  
  178.                         
  179.                         usflush(m->user);
  180.                         errcount2=0;
  181. rec_loop:
  182.                         
  183.                         chr = getchar_t(m->user);
  184.                         if (chr == CAN) {
  185.                                 if (two_can)  {
  186.                                         mspause(3000L);
  187.                                         print_text(m,"\nxmodem: Abort request received\n");
  188.                                         fclose(fp);
  189.                                         return(1);
  190.                                 }
  191.                                 two_can=1;
  192.                         } else {       
  193.                                 two_can=0;
  194.                         }
  195.                         
  196.                         if (chr == ACK)
  197.                                 break;                /* got it! */
  198.                          /* noise on line? */
  199.                         if (chr != NAK ) {
  200.                                 ++errcount2;
  201.                                 if (errcount2>=MAXERRORS) {
  202.                                           error(m);
  203.                                           fclose(fp);
  204.                                           return 1;
  205.                                 }
  206.                                 goto rec_loop;   
  207.                         }        
  208.                         errcount++;
  209.                 }
  210.                 if (errcount >= MAXERRORS) {
  211.                         error(m);
  212.                         fclose(fp);
  213.                         return(1);
  214.                 }
  215.                 block++;
  216.         }
  217.         errcount = 0;
  218.         while (errcount < MAXERRORS) {
  219.                 usputc(m->user,EOT);
  220.                 usflush(m->user);
  221.                 if (getchar_t(m->user) == ACK)
  222.                         {
  223.                         fclose(fp);
  224.                         mspause(6000L);
  225.                         log(m->user,"Xmodem: Download - %s",tfile);
  226.                         print_text(m,"Xmodem: File sent OK\n");
  227.                         return(0);
  228.                         }
  229.                 errcount++;
  230.         }
  231.         fclose(fp);
  232.         mspause(3000L);
  233.         error(m);
  234.         return(1);
  235. }
  236.  
  237. /* receive a file from the remote */
  238. static int
  239. recvfile(tfile, m)
  240. char *tfile;
  241. struct mbx *m;
  242. {
  243.         FILE *fp;
  244.         unsigned char hdr, blk, cblk, tmp, cksum, crc1, crc2;
  245.         unsigned char c1, c2, sum, block, sector[SECSIZE];
  246.         unsigned char first, mode, errcount, two_can;
  247.         int i;
  248.        
  249.         if (!access(tfile, 00)) {
  250.                 print_text(m,"xmodem: File %s already exists\n",tfile);
  251.                 return(1);
  252.         }
  253.  
  254.         if (!(fp = fopen(tfile, WRITE_BINARY))) {
  255.              print_text(m,"xmodem: Can't open '%s' for write\n", tfile);
  256.              return(1);
  257.         }
  258.         print_text(m,"File open - ready to receive\n");
  259.         print_text(m,"To cancel: use CTRL-X numerous times\n");
  260.         mspause(3000L);
  261.         rawmode(m);  
  262.         errcount = 0;
  263.         block = 1;
  264.         first=0;
  265.         two_can=0;
  266.         
  267.         mspause(3000L);
  268.         while (errcount < MAXERRORS) {
  269.                 if (errcount < (MAXERRORS / 2)) {
  270.                       usputc(m->user,'C');                /* try CRC mode first */
  271.                       usflush(m->user);
  272.                       mode = 1;
  273.                 }
  274.                 else {
  275.                       usputc(m->user,NAK);                /* then checksum */
  276.                       usflush(m->user);
  277.                       mode = 0;
  278.                 }
  279.                 if ((hdr = getchar_t(m->user)) == SOH) {
  280.                         first=1;
  281.                         break;
  282.                 }
  283.                 if (hdr == CAN) {
  284.                         if (two_can){
  285.                                 mspause(3000L);
  286.                                 print_text(m,"\nxmodem: Abort request received\n");
  287.                                 fclose(fp);
  288.                                 unlink(tfile);
  289.                                 return(1);
  290.                         }      
  291.                         two_can=1;
  292.                 } else {       
  293.                         two_can=0;
  294.                 }
  295.                 errcount++;
  296.         }
  297.         if (errcount >= MAXERRORS) {
  298.                 mspause(3000L);
  299.                 print_text(m,"\nxmodem: Timed out on acknowledge\n");
  300.                 fclose(fp);
  301.                 unlink(tfile);
  302.                 return(1);
  303.         }
  304.         errcount = 0;
  305.         two_can=0;
  306.         while (errcount < MAXERRORS) {
  307.                 
  308.                 if (first) {
  309.                         hdr=SOH;
  310.                         first=0;
  311.                 } else
  312.                         hdr = getchar_t(m->user);
  313.                 
  314.                 if (hdr == CAN) {
  315.                         if (two_can){
  316.                                 mspause(3000L);
  317.                                 print_text(m,"\nxmodem: Abort request received\n");
  318.                                 fclose(fp);
  319.                                 unlink(tfile);
  320.                                 return(1);
  321.                         }      
  322.                         two_can=1;
  323.                         continue;
  324.                 } else {       
  325.                         two_can=0;
  326.                 }
  327.                 
  328.                 if (hdr == EOT)                        /* done! */
  329.                         break;
  330.                 
  331.                 if (hdr != SOH) {             /* read in junk for 6 seconds */
  332.                         alarm(6000L);
  333.                         while(errno != EALARM)
  334.                               rrecvchar(m->user);          
  335.                         alarm(0L);   /* cancel alarm */
  336.                         first=0;
  337.                         goto nak;
  338.                 }
  339.                 blk = getchar_t(m->user);
  340.                 cblk = getchar_t(m->user);
  341.                 crc1 = 0;
  342.                 crc2 = 0;
  343.                 sum = 0;
  344.                 for (i=0; i < SECSIZE; i++) {
  345.                         sector[i] = getchar_t(m->user);
  346.                         if (mode)
  347.                                 update_crc(sector[i],&crc1,&crc2);
  348.                         else
  349.                                 sum += sector[i];
  350.                 }
  351.                 if (mode) {
  352.                         c1 = getchar_t(m->user);
  353.                         c2 = getchar_t(m->user);
  354.                 }
  355.                 else
  356.                         cksum = getchar_t(m->user);
  357.                 if (blk != block && blk != (block - 1))
  358.                         goto nak;
  359.                 tmp = ~blk;
  360.                 if (cblk != tmp)
  361.                         goto nak;
  362.                 if (mode) {
  363.                         update_crc(0,&crc1,&crc2);
  364.                         update_crc(0,&crc1,&crc2);
  365.                         if (c1 != crc1 || c2 != crc2)
  366.                                 goto nak;
  367.                 }
  368.                 else {
  369.                         if (cksum != sum)
  370.                                 goto nak;
  371.                 }
  372.                 if (block == blk) {
  373.                   fflush(fp);
  374.                   if (fwrite(sector, sizeof(sector[0]), SECSIZE, fp)!=SECSIZE){
  375.                         error(m);
  376.                         print_text(m,"         File write error - Partial file deleted\n");
  377.                         fclose(fp);
  378.                         unlink(tfile);
  379.                         return (1);
  380.                   }
  381.                 }
  382.                 block = blk + 1;
  383.                 usputc(m->user,ACK);                        /* got it! */
  384.                 usflush(m->user);
  385.                 errcount = 0;
  386.                 continue;
  387.  
  388.     nak:        usputc(m->user,NAK);                    /* do it over */
  389.                 usflush(m->user);
  390.                 errcount++;
  391.         }
  392.         if (errcount == MAXERRORS) {
  393.                 error(m);
  394.                 fclose(fp);
  395.                 unlink(tfile);
  396.                 return(1);
  397.         }
  398.         usputc(m->user,ACK);
  399.         usflush(m->user);
  400.         mspause(3000L);
  401.         fclose(fp);
  402.         log(m->user,"Xmodem: Upload - %s",tfile);
  403.         print_text(m,"Xmodem: File received OK\n");
  404.         return(0);
  405. }        
  406.  
  407. /* exceeded the maximum number of retry's */
  408. static void
  409. error(m)
  410. struct mbx *m;
  411. {
  412.         int i;
  413.         
  414.         for(i=0;i<9;i++) {
  415.                 usputc(m->user,CAN);
  416.         }
  417.         usflush(m->user);
  418.         mspause(1000L);
  419.         for(i=0;i<9;i++) {
  420.                 usputc(m->user,BS);
  421.         }
  422.         usflush(m->user);
  423.         mspause(3000L);
  424.         print_text(m,"\nxmodem: Exceeded error limit...aborting\n");
  425.         return;
  426. }
  427.  
  428. /* update the CRC bytes */
  429. static void
  430. update_crc(c, crc1, crc2)
  431. unsigned char c, *crc1, *crc2;
  432. {
  433.         register int i, temp;
  434.         register unsigned char carry, c_crc1, c_crc2;
  435.         
  436.         for (i=0; i < 8; i++) {
  437.                 temp = c * 2;
  438.                 c = temp;                        /* rotate left */
  439.                 carry = ((temp > 255) ? 1 : 0);
  440.                 temp = *crc2 * 2;
  441.                 *crc2 = temp;
  442.                 *crc2 |= carry;                        /* rotate with carry */
  443.                 c_crc2 = ((temp > 255) ? 1 : 0);
  444.                 temp = *crc1 * 2;
  445.                 *crc1 = temp;
  446.                 *crc1 |= c_crc2;
  447.                 c_crc1 = ((temp > 255) ? 1 : 0);
  448.                 if (c_crc1) {
  449.                         *crc2 ^= 0x21;
  450.                         *crc1 ^= 0x10;
  451.                 }
  452.         }
  453.         return;
  454. }
  455.  
  456. /* getchar with a 5 sec time out */
  457. static char
  458. getchar_t(s)
  459. int s;
  460. {
  461.         char c;
  462.         /* only have 5 sec... */ 
  463.         alarm(5000L);
  464.         /* Wait for something to happen */
  465.         c=rrecvchar(s); 
  466.         alarm(0L);
  467.         return(c);
  468. }
  469.                           
  470. /* put the stdin/stdout in the "raw" mode */
  471. static void 
  472. rawmode(m)
  473. struct mbx *m;
  474. {
  475.         seteol(m->user,0);
  476.         seteol(m->tip->s,0);
  477.         sockmode(m->tip->s,SOCK_BINARY);
  478.         sockmode(m->user,SOCK_BINARY);
  479.         m->tip->raw=1;
  480. }
  481.  
  482. static void 
  483. restoremode(m)
  484. struct mbx *m;
  485. {
  486.         while(socklen(m->user,0) != 0)
  487.            recv_mbuf(m->user,NULL,0,NULLCHAR,0); 
  488.         seteol(m->user,"\n");
  489.         seteol(m->tip->s,"\n");
  490.         sockmode(m->user,SOCK_ASCII);
  491.         sockmode(m->tip->s,SOCK_ASCII);
  492.         m->tip->raw=0;
  493. }
  494.  
  495. void
  496. #ifdef TNOS_68K
  497. print_text(m, fmt)
  498. struct mbx *m;
  499. char *fmt;
  500. #else
  501. print_text (struct mbx *m,char *fmt, ...)
  502. #endif
  503. {
  504.         va_list ap;
  505.         char buf[80];
  506.  
  507.         restoremode(m);       
  508.         va_start(ap,fmt);
  509.         vsprintf(buf,fmt,ap);
  510.         va_end(ap);
  511.         usprintf(m->user,buf);
  512.         usflush(m->user);
  513. }        
  514.  
  515. #endif
  516.